package com.jse;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;

/**
 * token编码工具类
 * @author ouyangjun
 */
public class Tokens {
	
	private static Map<String,String> MAP_TOKENS = new HashMap<String,String>();
	private static final int VALID_TIME = 60*60*2; // token有效期(秒)
	public static final String TOKEN_ERROR = "F"; // 非法
	public static final String TOKEN_OVERDUE = "G"; // 过期
	public static final String TOKEN_FAILURE = "S"; // 失效
	public static Set<Map<String,Object>> cache;
	
	// 编码密码,可自定义
	private static final String ENCODED_PASSWORD = "iepsy";
	
	/**
	 * 编码
	 * @param str
	 * @return
	 */
	public static String encoded(String str) {
		return strToHex(encodedString(str, ENCODED_PASSWORD));
	}
	
	/**
	 * 转换
	 * @param str
	 * @param password
	 * @return
	 */
	private static String encodedString(String str, String password) {
		char[] pwd = password.toCharArray();
		int pwdLen = pwd.length;
		
        char[] strArray = str.toCharArray();
        for (int i=0; i<strArray.length; i++) {
        	strArray[i] = (char)(strArray[i] ^ pwd[i%pwdLen] ^ pwdLen);
        }
        return new String(strArray);
	}
	
	private static String strToHex(String s) {
		return bytesToHexStr(s.getBytes());
	}
	
	private static String bytesToHexStr(byte[] bytesArray) {
		StringBuilder builder = new StringBuilder();
		String hexStr;
		for (byte bt : bytesArray) {
			hexStr = Integer.toHexString(bt & 0xFF);
			if (hexStr.length() == 1) {
				builder.append("0");
				builder.append(hexStr);
			}else{
				builder.append(hexStr);
			}
		}
		return builder.toString();
	}
	
	/**
	 * 解码
	 * @param str
	 * @return
	 */
	public static String decoded(String str) {
		String hexStr = null;
		try {
			hexStr = hexStrToStr(str);
		} catch (Exception e) {
			Log.get("tokens").warn("decoded : {}",e);
		}
		if (hexStr != null) {
			hexStr = encodedString(hexStr, ENCODED_PASSWORD);
		}
		return hexStr;
	}
	
	private static String hexStrToStr(String hexStr) {
		return new String(hexStrToBytes(hexStr));
	}
	
	private static byte[] hexStrToBytes(String hexStr) {
		String hex;
		int val;
		byte[] btHexStr = new byte[hexStr.length()/2];
		for (int i=0; i<btHexStr.length; i++) {
			hex = hexStr.substring(2*i, 2*i+2);
			val = Integer.valueOf(hex, 16);
			btHexStr[i] = (byte) val;
		}
		return btHexStr;
	}
	
	/**
	 * 生成token,该token长度不一致,如需一致,可自行MD5或者其它方式加密一下
	 * 该方式的token只存在磁盘上,如果项目是分布式,最好用redis存储
	 * @param str: 该字符串可自定义,在校验token时要保持一致
	 * @return
	 */
	public static String getToken(String str) {
		String token = encoded(getCurrentTime()+","+str);
		MAP_TOKENS.put(str, token);
		return token;
	}
	
	/**
	 * 校验token的有效性
	 * @param token
	 * @return
	 */
	public static String checkToken(String token) {
		if (token == null) {
			return TOKEN_ERROR;
		}
		try{
			String[] tArr = decoded(token).split(",");
			if (tArr.length != 2) {
				return TOKEN_ERROR;
			}
			// token生成时间戳
			int tokenTime = Integer.parseInt(tArr[0]);
			// 当前时间戳
			int currentTime = getCurrentTime();
			if (currentTime-tokenTime < VALID_TIME) {
				String tokenStr = tArr[1];
				String mToken = MAP_TOKENS.get(tokenStr);
				if (mToken == null) {
					return TOKEN_OVERDUE;
				} else if(!mToken.equals(token)) {
					return TOKEN_FAILURE;
				}
				return tokenStr;
			} else {
				return TOKEN_OVERDUE;
			}
		}catch (Exception e) {
			Log.get("tokens").warn("checkToken : {}",e);
		}
		return TOKEN_ERROR;
	}
	
	/**获取当前时间戳（10位整数）*/
	public static int getCurrentTime() {
		return (int)(System.currentTimeMillis()/1000);
	}
	
	/**
	 * 移除过期的token
	 */
	public static void removeInvalidToken() {
		int currentTime = getCurrentTime();
		for (Entry<String,String> entry : MAP_TOKENS.entrySet()) {
			String[] tArr = decoded(entry.getValue()).split(",");
			int tokenTime = Integer.parseInt(tArr[0]);
			if(currentTime-tokenTime > VALID_TIME){
				MAP_TOKENS.remove(entry.getKey());
			}
		}
	}
	
	private static Random random = new Random();
	
	
//	/**
//	 * 
//	 * @param req
//	 * @param name def _jse_token
//	 * @param seconds
//	 */
//	public static void create(HttpServletRequest req,String name, int seconds) {
//		if (cache == null) {
//			String tokenId = String.valueOf(random.nextLong());
//			req.setAttribute(name, tokenId);
//			req.getSession().setAttribute(name, tokenId);
//			StringBuilder sb = new StringBuilder();
//			sb.append("<input type='hidden' name='").append(name).append("' id='").append(name).append("' value='").append(tokenId).append("' />");
//			req.setAttribute("token", sb.toString());
//		}
//		else {
//			if (seconds < 300) {
//				seconds = 300;
//			}
//			String tokenId = null;
//			Map<String,Object> token = null;
//			int safeCounter = 8;
//			do {
//				if (safeCounter-- == 0) {
//					throw new RuntimeException("Can not create tokenId.");
//				}
//				tokenId = String.valueOf(random.nextLong());
//				token = new HashMap<String, Object>();
//				token.put("id", tokenId);
//				token.put("expirationTime", System.currentTimeMillis() + (seconds * 1000));
//			} while(tokenId == null || cache.contains(token));
//			
//			req.setAttribute(name, tokenId);
//			cache.add(token);
//			StringBuilder sb = new StringBuilder();
//			sb.append("<input type='hidden' name='").append(name).append("' id='").append(name).append("' value='").append(tokenId).append("' />");
//			req.setAttribute("token", sb.toString());
//		}
//	}
//	
//	/**
//	 * Check token to prevent resubmit.
//	 * @param name the token name used in view's form
//	 * @return true if token is correct
//	 */
//	public static boolean validate(HttpServletRequest req, String name) {
//		String clientTokenId = req.getParameter(name);
//		if (cache == null) {
//			String serverTokenId = req.getSession().getAttribute(name).toString();
//			req.getSession().removeAttribute(name);		// important!
//			return Strings.isNotBlank(clientTokenId) && clientTokenId.equals(serverTokenId);
//		}
//		else {
//			Map<String,Object> token = new HashMap<String, Object>();
//			token.put("id",clientTokenId);
//			boolean result = cache.contains(token);
//			cache.remove(token);
//			return result;
//		}
//	}
	
	/**
	 * 测试
	 * @param args
	 */
	public static void main(String[] args) {
		String str = "bjjyxz|b547635d7b020385e9e9b3bbed5a71e3";
		
		// 获取token
		String token = getToken(str);
		System.out.println("token Result: " + token);
		
		// 校验token
		String checkToken = checkToken(token);
		System.out.println("checkToken Result: " + checkToken);
		if(str.equals(checkToken)) {
			System.out.println("==>token verification succeeded!");
		}
		
	}
}
